Tubes = Tubes or {}
Tubes.Debug = SinglePlayer () or (GetConVar ("sensitivity") and true or false)
Tubes.Resources = {}

if Tubes.DispatchEvent then
	Tubes:DispatchEvent ("Unload")
end

function Tubes.AddResource (path)
	Tubes.Resources [path] = true
end

function Tubes.MakeConstructor (metatable)
	return function (...)
		local object = {}
		setmetatable (object, metatable)
		object:ctor (...)
		return object
	end
end

if SERVER then
	function Tubes.AddLuaFolder (folder)
		local files = file.FindInLua (folder .. "/*")
		for _, fileName in pairs (files) do
			if fileName:sub (-4) == ".lua" then
				AddCSLuaFile (folder .. "/" .. fileName)
			end
		end
	end

	function Tubes.AddLuaFolderRecursive (folder)
		Tubes.AddLuaFolder (folder)
		local folders = file.FindDir ("../lua/" .. folder .. "/*")
		for _, v in pairs (folders) do
			Tubes.AddLuaFolderRecursive (folder .. "/" .. v)
		end
	end
	
	if not Tubes.Debug then
		Tubes.AddLuaFolderRecursive ("tubes")
	end
end

function Tubes.GetPlayerSteamID (ply)
	if SinglePlayer () then
		return "STEAM_0:0:0"
	end
	if type (ply) == "Player" and
		ply.SteamID then
		return ply:SteamID ()
	end
	return type (ply) == "string" and ply or "UNKNOWN"
end

include ("Unicode.lua")
include ("StringPool.lua")
include ("EventProvider.lua")
Tubes.EventProvider (Tubes)
include ("net/Networking.lua")

include ("PermissionBlock.lua")
include ("PermissionGroup.lua")
include ("Permissions.lua")

include ("Client.lua")
include ("Clients.lua")

include ("FileSystem.lua")
include ("FileTypes.lua")

if CLIENT then
	include ("ui/controls.lua")
	include ("ui/permissions.lua")
	include ("Editor.lua")
	include ("FileSystemBrowser.lua")
	include ("GroupBrowser.lua")
else
	include ("Resources.lua")
end

Tubes:DispatchEvent ("Initialize")

-- Events
local QueuedPlayers = {}
hook.Add (CLIENT and "OnEntityCreated" or "PlayerInitialSpawn", "Tubes.PlayerConnected", function (ply)
	if type (ply) == "Player" then
		QueuedPlayers [ply] = true
	end
end)

hook.Add ("Think", "Tubes.PlayerConnected", function ()
	for Player, _ in pairs (QueuedPlayers) do
		if Player:IsValid () and
			Player.SteamID and
			Player:Name () ~= "unconnected" then
			local SteamID = Player:SteamID ()
			if SteamID == "BOT" or SteamID == "NULL" then
				QueuedPlayers [Player] = nil
			elseif SteamID ~= "STEAM_ID_PENDING" then
				QueuedPlayers [Player] = nil
				local IsLocalPlayer = CLIENT and Player == LocalPlayer () or false
				Tubes:DispatchEvent ("PlayerConnected", Player, IsLocalPlayer)
				if IsLocalPlayer then
					Tubes:DispatchEvent ("LocalPlayerConnected", Player)
				end
			end
		end
	end
end)

hook.Add ("EntityRemoved", "Tubes.PlayerDisconnected", function (ply)
	if type (ply) == "Player" and
		ply:IsValid () then
		ErrorNoHalt (tostring (ply) .. " removed.\n")
		Tubes:DispatchEvent ("PlayerDisconnected", ply)
	end
end)

for _, Player in ipairs (player.GetAll ()) do
	QueuedPlayers [Player] = true
end

Tubes:AddEventListener ("Unload", function ()
	hook.Remove (CLIENT and "OnEntityCreated" or "PlayerInitialSpawn", "Tubes.PlayerConnected")
	hook.Remove ("Think", "Tubes.PlayerConnected")
	hook.Remove ("EntityRemoved", "Tubes.PlayerDisconnected")
end)

-- Console commands
if CLIENT then
	concommand.Add ("tubes_dump_resources", function ()
		local Resources = {}
		for Resource, _ in pairs (Tubes.Resources) do
			Resources [#Resources + 1] = Resource
		end
		table.sort (Resources, function (a, b)
			return a:lower () < b:lower ()
		end)
		
		local File = ""
		print (tostring (#Resources) .. " resources.")
		for i = 1, #Resources do
			print (Resources [i])
			File = File .. "resource.AddFile (\"" .. Resources [i] .. "\")\n"
		end
		file.Write ("Resources_lua.txt", File)
	end)
end

concommand.Add ("tubes_reload" .. (SERVER and "_sv" or ""), function ()
	include ("autorun/tubes.lua")
end)